#include "U2GLESTextureManager.h"

#include "U2GLESRenderTexture.h"
#include "U2Root.h"
#include "U2RenderSystem.h"


U2EG_NAMESPACE_USING


U2GLESTextureManager::U2GLESTextureManager(U2GLESSupport& support)
: U2TextureManager()
, mGLSupport(support)
, mWarningTextureID(0)
{
    GL_CHECK_ERROR;
    // Register with group manager
    U2ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this);

    createWarningTexture();
}

U2GLESTextureManager::~U2GLESTextureManager()
{
    // Unregister with group manager
    U2ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType);
    // Delete warning texture
    glDeleteTextures(1, &mWarningTextureID);
    GL_CHECK_ERROR;
}

U2Resource* U2GLESTextureManager::createImpl(const U2String& name, U2ResourceHandle handle, 
                                       const U2String& group, bool isManual,
                                       U2ManualResourceLoader* loader,
                                       const NameValuePairList* createParams)
{
    return U2_NEW U2GLESTexture(this, name, handle, group, isManual, loader, mGLSupport);
}

//-----------------------------------------------------------------------------
void U2GLESTextureManager::createWarningTexture()
{
    // Generate warning texture
    size_t width = 8;
    size_t height = 8;

    // TODO convert to 5_6_5
    u2uint8* data = new u2uint8[width * height * 3]; // 0xXXRRGGBB

    // Yellow/black stripes
    for(size_t y = 0; y < height; ++y)
    {
        for(size_t x = 0; x < width; ++x)
        {
            int index = (y * width + x) * 3;
            if (((x + y) % 8) < 4)
            {
                data[index++] = (u2uint8)0;
                data[index++] = (u2uint8)0;
                data[index++] = (u2uint8)0;
            }
            else {
                data[index++] = (u2uint8)255;
                data[index++] = (u2uint8)255;
                data[index++] = (u2uint8)0;
            }
        }
    }

    // Create GL resource
    glGenTextures(1, &mWarningTextureID);
    GL_CHECK_ERROR;
    glBindTexture(GL_TEXTURE_2D, mWarningTextureID);
    GL_CHECK_ERROR;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
        GL_UNSIGNED_BYTE, (void*)data);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    GL_CHECK_ERROR;
    // Free memory
    delete [] data;
}

PixelFormat U2GLESTextureManager::getNativeFormat(TextureType ttype, PixelFormat format, int usage)
{
    // Adjust requested parameters to capabilities
    const U2RenderSystemCapabilities *caps = U2Root::getSingleton().getRenderSystem()->getCapabilities();

    // Check compressed texture support
    // if a compressed format not supported, revert to PF_A8R8G8B8
    if (U2PixelUtil::isCompressed(format) &&
        !caps->hasCapability(RSC_TEXTURE_COMPRESSION_DXT) && !caps->hasCapability(RSC_TEXTURE_COMPRESSION_PVRTC))
    {
        return PF_A8R8G8B8;
    }
    // if floating point textures not supported, revert to PF_A8R8G8B8
    if (U2PixelUtil::isFloatingPoint(format) &&
        !caps->hasCapability(RSC_TEXTURE_FLOAT))
    {
        return PF_A8R8G8B8;
    }

    // Check if this is a valid rendertarget format
    if (usage & TU_RENDERTARGET)
    {
        /// Get closest supported alternative
        /// If mFormat is supported it's returned
        return U2GLESRTTManager::getSingleton().getSupportedAlternative(format);
    }

    // Supported
    return format;
}

bool U2GLESTextureManager::isHardwareFilteringSupported(TextureType ttype, PixelFormat format, int usage,
        bool preciseFormatOnly)
{
    if (format == PF_UNKNOWN)
    {
        return false;
    }

    // Check native format
    PixelFormat nativeFormat = getNativeFormat(ttype, format, usage);
    if (preciseFormatOnly && format != nativeFormat)
    {
        return false;
    }

    // Assume non-floating point is supported always
    if (!U2PixelUtil::isFloatingPoint(nativeFormat))
    {
        return true;
    }

    return false;
}